home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2001 September / PC-WELT 9-2001.ISO / software / hw / brennen / flask_src.exe / Resizer / VBitmap.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-06  |  13.3 KB  |  567 lines

  1. /* 
  2.  *  vbitmap.cpp   - Original code from Avery Lee's Virtual Dub
  3.  *
  4.  *    Copyright (C) Alberto Vigata - ultraflask@yahoo.com - January 2000
  5.  *
  6.  *  This file is part of FlasKMPEG, a free MPEG to MPEG/AVI converter
  7.  *    
  8.  *  FlasKMPEG is free software; you can redistribute it and/or modify
  9.  *  it under the terms of the GNU General Public License as published by
  10.  *  the Free Software Foundation; either version 2, or (at your option)
  11.  *  any later version.
  12.  *   
  13.  *  FlasKMPEG is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *  GNU General Public License for more details.
  17.  *   
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with GNU Make; see the file COPYING.  If not, write to
  20.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  21.  *
  22.  */
  23.  
  24.  
  25.  
  26. #include <crtdbg.h>
  27. #include <math.h>
  28.  
  29.  
  30. #include "convert.h"
  31. #include "VBitmap.h"
  32.  
  33.  
  34. #define FP_EPSILON (1e-30)
  35.  
  36. extern "C" void __cdecl asm_resize_nearest(
  37.         Pixel32 *dst,
  38.         Pixel32 *src,
  39.         long width,
  40.         PixDim height,
  41.         PixOffset dstpitch,
  42.         PixOffset srcpitch,
  43.         unsigned long xaccum,
  44.         unsigned long yaccum,
  45.         unsigned long xfrac,
  46.         unsigned long yfrac,
  47.         long xistep,
  48.         PixOffset yistep);
  49.  
  50. extern "C" void __cdecl asm_resize_bilinear(
  51.         void *dst,
  52.         void *src,
  53.         long w,
  54.         PixDim h,
  55.         PixOffset dstpitch,
  56.         PixOffset srcpitch,
  57.         unsigned long xaccum,
  58.         unsigned long yaccum,
  59.         unsigned long xfrac,
  60.         unsigned long yfrac,
  61.         long xistep,
  62.         PixOffset yistep,
  63.         long precopy,
  64.         long postcopy,
  65.         void *srclimit);
  66.  
  67. extern "C" void __cdecl asm_bitmap_xlat1(Pixel32 *dst, Pixel32 *src,
  68.         PixOffset dpitch, PixOffset spitch,
  69.         PixDim w,
  70.         PixDim h,
  71.         const Pixel8 *tbl);
  72.  
  73. extern "C" void __cdecl asm_bitmap_xlat3(Pixel32 *dst, Pixel32 *src,
  74.         PixOffset dpitch, PixOffset spitch,
  75.         PixDim w,
  76.         PixDim h,
  77.         const Pixel32 *tbl);
  78.  
  79. ///////////////////////////////////////////////////////////////////////////
  80.  
  81. VBitmap::VBitmap(void *lpData, BITMAPINFOHEADER *bmih) throw() {
  82.     init(lpData, bmih);
  83. }
  84.  
  85. VBitmap::VBitmap(void *data, PixDim w, PixDim h, int depth) throw() {
  86.     init(data, w, h, depth);
  87. }
  88.  
  89. ///////////////////////////////////////////////////////////////////////////
  90.  
  91. VBitmap& VBitmap::init(void *lpData, BITMAPINFOHEADER *bmih) throw() {
  92.     data            = (Pixel *)lpData;
  93.     palette            = (Pixel *)(bmih+1);
  94.     depth            = bmih->biBitCount;
  95.     w                = bmih->biWidth;
  96.     h                = bmih->biHeight;
  97.     offset            = 0;
  98.     AlignTo4();
  99.  
  100.     return *this;
  101. }
  102.  
  103. VBitmap& VBitmap::init(void *data, PixDim w, PixDim h, int depth) throw() {
  104.     this->data        = (Pixel32 *)data;
  105.     this->palette    = NULL;
  106.     this->depth        = depth;
  107.     this->w            = w;
  108.     this->h            = h;
  109.     this->offset    = 0;
  110.     AlignTo8();
  111.  
  112.     return *this;
  113. }
  114.  
  115. void VBitmap::MakeBitmapHeader(BITMAPINFOHEADER *bih) const throw() {
  116.     bih->biSize                = sizeof(BITMAPINFOHEADER);
  117.     bih->biBitCount            = depth;
  118.     bih->biPlanes            = 1;
  119.     bih->biCompression        = BI_RGB;
  120.  
  121.     if (pitch == ((w*bih->biBitCount + 31)/32) * 4)
  122.         bih->biWidth        = w;
  123.     else
  124.         bih->biWidth        = pitch*8 / depth;
  125.  
  126.     bih->biHeight            = h;
  127.     bih->biSizeImage        = pitch*h;
  128.     bih->biClrUsed            = 0;
  129.     bih->biClrImportant        = 0;
  130.     bih->biXPelsPerMeter    = 0;
  131.     bih->biYPelsPerMeter    = 0;
  132. }
  133.  
  134. void VBitmap::AlignTo4() throw() {
  135.     pitch        = PitchAlign4();
  136.     modulo        = Modulo();
  137.     size        = Size();
  138. }
  139.  
  140. void VBitmap::AlignTo8() throw() {
  141.     pitch        = PitchAlign8();
  142.     modulo        = Modulo();
  143.     size        = Size();
  144. }
  145.  
  146. ///////////////////////////////////////////////////////////////////////////
  147.  
  148. bool VBitmap::dualrectclip(PixCoord& x2, PixCoord& y2, const VBitmap *src, PixCoord& x1, PixCoord& y1, PixDim& dx, PixDim& dy) const throw() {
  149.     if (dx == -1) dx = src->w;
  150.     if (dy == -1) dy = src->h;
  151.  
  152.     // clip to source bitmap
  153.  
  154.     if (x1 < 0) { dx+=x1; x2-=x1; x1=0; }
  155.     if (y1 < 0) { dy+=y1; y2-=y1; y1=0; }
  156.     if (x1+dx > src->w) dx=src->w-x1;
  157.     if (y1+dy > src->h) dy=src->h-y1;
  158.  
  159.     // clip to destination bitmap
  160.  
  161.     if (x2 < 0) { dx+=x2; x1-=x2; x2=0; }
  162.     if (y2 < 0) { dy+=y2; y1-=y2; y2=0; }
  163.     if (x2+dx > w) dx=w-x2;
  164.     if (y2+dy > h) dy=h-y2;
  165.  
  166.     // anything left to blit?
  167.  
  168.     if (dx<=0 || dy<=0)
  169.         return false;
  170.  
  171.     return true;
  172. }
  173.  
  174. ///////////////////////////////////////////////////////////////////////////
  175.  
  176. void VBitmap::BitBlt(PixCoord x2, PixCoord y2, const VBitmap *src, PixDim x1, PixDim y1, PixDim dx, PixDim dy) const throw() {
  177.     static void (*converters[3][3])(void *dest, long dest_pitch, void *src, long src_pitch, long width, long height) = {
  178.         { DIBconvert_16_to_16, DIBconvert_24_to_16, DIBconvert_32_to_16, },
  179.         { DIBconvert_16_to_24, DIBconvert_24_to_24, DIBconvert_32_to_24, },
  180.         { DIBconvert_16_to_32, DIBconvert_24_to_32, DIBconvert_32_to_32, },
  181.     };
  182.  
  183.     Pixel *dstp, *srcp;
  184.  
  185.     _ASSERT(depth >= 16);    // we only blit to 16/24/32
  186.  
  187.     if (!dualrectclip(x2, y2, src, x1, y1, dx, dy))
  188.         return;
  189.  
  190.     // compute coordinates
  191.  
  192.     srcp = src->Address(x1, y1+dy-1);
  193.     dstp = Address(x2, y2+dy-1);
  194.  
  195.     // are we blitting from an 8-bit bitmap?
  196.  
  197.     //CHECK_FPU_STACK
  198.  
  199.     if (src->depth == 8)
  200.         switch(depth) {
  201.         case 32:
  202.             DIBconvert_8_to_32(dstp, pitch, srcp, src->pitch, dx, dy, src->palette);
  203.             break;
  204.         case 24:
  205.             DIBconvert_8_to_24(dstp, pitch, srcp, src->pitch, dx, dy, src->palette);
  206.             break;
  207.         case 16:
  208.             DIBconvert_8_to_16(dstp, pitch, srcp, src->pitch, dx, dy, src->palette);
  209.             break;
  210.         }
  211.     else {
  212.         converters[depth/8-2][src->depth/8-2](dstp, pitch, srcp, src->pitch, dx, dy);
  213.     }
  214.  
  215.     //CHECK_FPU_STACK
  216. }
  217.  
  218. void VBitmap::BitBltDither(PixCoord x2, PixCoord y2, const VBitmap *src, PixDim x1, PixDim y1, PixDim dx, PixDim dy, bool to565) const throw() {
  219.  
  220.     // Right now, we can only dither 32->16
  221.  
  222.     if (src->depth != 32 || depth != 16) {
  223.         BitBlt(x2, y2, src, x1, y1, dx, dy);
  224.         return;
  225.     }
  226.  
  227.     // Do the blit
  228.  
  229.     Pixel *dstp, *srcp;
  230.  
  231.     if (!dualrectclip(x2, y2, src, x1, y1, dx, dy))
  232.         return;
  233.  
  234.     // compute coordinates
  235.  
  236.     srcp = src->Address(x1, y1+dy-1);
  237.     dstp = Address(x2, y2+dy-1);
  238.  
  239.     // do the blit
  240.  
  241.     //CHECK_FPU_STACK
  242.  
  243.     if (to565)
  244.         DIBconvert_32_to_16_565_dithered(dstp, pitch, srcp, src->pitch, dx, dy);
  245.     else
  246.         DIBconvert_32_to_16_dithered(dstp, pitch, srcp, src->pitch, dx, dy);
  247.  
  248.     //CHECK_FPU_STACK
  249. }
  250.  
  251. void VBitmap::BitBlt565(PixCoord x2, PixCoord y2, const VBitmap *src, PixDim x1, PixDim y1, PixDim dx, PixDim dy) const throw() {
  252.  
  253.     // Right now, we can only convert 32->16/565
  254.  
  255.     if (src->depth != 32 || depth != 16) {
  256.         BitBlt(x2, y2, src, x1, y1, dx, dy);
  257.         return;
  258.     }
  259.  
  260.     // Do the blit
  261.  
  262.     Pixel *dstp, *srcp;
  263.  
  264.     if (!dualrectclip(x2, y2, src, x1, y1, dx, dy))
  265.         return;
  266.  
  267.     // anything left to blit?
  268.  
  269.     if (dx<=0 || dy<=0) return;
  270.  
  271.     // compute coordinates
  272.  
  273.     srcp = src->Address(x1, y1+dy-1);
  274.     dstp = Address(x2, y2+dy-1);
  275.  
  276.     // do the blit
  277.  
  278.     //CHECK_FPU_STACK
  279.  
  280.     DIBconvert_32_to_16_565(dstp, pitch, srcp, src->pitch, dx, dy);
  281.  
  282.     //CHECK_FPU_STACK
  283. }
  284.  
  285. bool VBitmap::BitBltXlat1(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const Pixel8 *tbl) const throw() {
  286.     if (depth != 32)
  287.         return false;
  288.  
  289.     if (!dualrectclip(x2, y2, src, x1, y1, dx, dy))
  290.         return false;
  291.  
  292.     // do the translate
  293.  
  294.     asm_bitmap_xlat1(
  295.             this->Address32(x2, y2+dy-1)+dx,
  296.             src ->Address32(x1, y1+dy-1)+dx,
  297.             this->pitch,
  298.             src->pitch,
  299.             -4*dx, dy, tbl);
  300.  
  301.     return true;
  302. }
  303.  
  304. bool VBitmap::BitBltXlat3(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const Pixel32 *tbl) const throw() {
  305.     if (depth != 32)
  306.         return false;
  307.  
  308.     if (!dualrectclip(x2, y2, src, x1, y1, dx, dy))
  309.         return false;
  310.  
  311.     // do the translate
  312.  
  313.     asm_bitmap_xlat3(
  314.             this->Address32(x2, y2+dy-1)+dx,
  315.             src ->Address32(x1, y1+dy-1)+dx,
  316.             this->pitch,
  317.             src->pitch,
  318.             -4*dx, dy, tbl);
  319.  
  320.     return true;
  321. }
  322.  
  323. ///////////////////////////////////////////////////////////////////////////
  324.  
  325. static __int64 sbnf_correct(double x, double y) {
  326.     __int64 v;
  327.  
  328.     x = x * 4294967296.0;
  329.  
  330.     if (x < 0.0)
  331.         v = (__int64)(x - 0.5);
  332.     else
  333.         v = (__int64)(x + 0.5);
  334.  
  335.     if (y<0.0 && v) ++v;
  336.     if (y>0.0 && v) --v;
  337.  
  338.     return v;
  339. }
  340.  
  341. bool VBitmap::StretchBltNearestFast(PixCoord x2, PixCoord y2, PixDim dx, PixDim dy,
  342.                         const VBitmap *src, double x1, double y1, double dx1, double dy1) const throw() {
  343.  
  344.     // No format conversions!!
  345.  
  346.     if (src->depth != depth)
  347.         return false;
  348.  
  349.     // Right now, only do 32-bit stretch.  (24-bit is a pain, 16-bit is slow.)
  350.  
  351.     if (depth != 32)
  352.         return false;
  353.  
  354.     // Funny values?
  355.     
  356.     if (dx <= 0 || dy <= 0)
  357.         return false;
  358.  
  359.     // Check for destination clipping and abort if so.
  360.  
  361.     if (x2 < 0 || y2 < 0 || x2+dx > w || y2+dy > h)
  362.         return false;
  363.  
  364.     // Check for source clipping.  Trickier, since we permit source flips.
  365.  
  366.     if (x1 < 0.0 || y1 < 0.0 || x1+dx1 < 0.0 || y1+dy1 < 0.0)
  367.         return false;
  368.  
  369.     if (x1 > src->w || y1 > src->h || x1+dx1 > src->w || y1+dy1 > src->h)
  370.         return false;
  371.  
  372.     // Compute step values.
  373.  
  374.     __int64 xfrac64, yfrac64, xaccum64, yaccum64;
  375.     unsigned long xfrac, yfrac;
  376.     int xistep;
  377.     PixOffset yistep;
  378.  
  379. /*    xfrac64 = sbnf_correct(dx1, dx1) / dx;    // round toward zero to avoid exceeding buffer
  380.     yfrac64 = sbnf_correct(dy1, dy1) / dy;*/
  381.     xfrac64 = dx1*4294967296.0 / dx;    // round toward zero to avoid exceeding buffer
  382.     yfrac64 = dy1*4294967296.0 / dy;
  383.  
  384.     xfrac = (unsigned long)xfrac64;
  385.     yfrac = (unsigned long)yfrac64;
  386.  
  387.     xistep = (long)(xfrac64 >> 32);            // round toward -oo
  388.     yistep = (long)(yfrac64 >> 32) * src->pitch;
  389.  
  390.     xaccum64 = sbnf_correct(x1, -dx1) + xfrac64/2;
  391.     yaccum64 = sbnf_correct(y1, -dy1) + yfrac64/2;
  392.  
  393.     // Call texturing routine.
  394.  
  395.     asm_resize_nearest(
  396.             Address32i(x2, y2) + dx,            // destination pointer, right side
  397.             src->Address32i((long)(xaccum64>>32), (long)(yaccum64>>32)),
  398.             -dx*4,
  399.             dy,
  400.             pitch,
  401.             src->pitch,
  402.             (unsigned long)xaccum64,
  403.             (unsigned long)yaccum64,
  404.             xfrac,
  405.             yfrac,
  406.             xistep,
  407.             yistep);
  408.  
  409.     return true;
  410. }
  411.  
  412. bool VBitmap::StretchBltBilinearFast(PixCoord x2, PixCoord y2, PixDim dx, PixDim dy,
  413.                         const VBitmap *src, double x1, double y1, double dx1, double dy1) const throw() {
  414.  
  415.     // No format conversions!!
  416.  
  417.     if (src->depth != depth)
  418.         return false;
  419.  
  420.     // Right now, only do 32-bit stretch.  (24-bit is a pain, 16-bit is slow.)
  421.  
  422.     if (depth != 32)
  423.         return false;
  424.  
  425.     // Funny values?
  426.     
  427.     if (dx <= 0 || dy <= 0)
  428.         return false;
  429.  
  430.     // Check for destination clipping and abort if so.
  431.  
  432.     if (x2 < 0 || y2 < 0 || x2+dx > w || y2+dy > h)
  433.         return false;
  434.  
  435.     // Check for source clipping.  Trickier, since we permit source flips.
  436.  
  437.     if (x1 < 0.0 || y1 < 0.0 || x1+dx1 < 0.0 || y1+dy1 < 0.0)
  438.         return false;
  439.  
  440.     if (x1 > src->w || y1 > src->h || x1+dx1 > src->w || y1+dy1 > src->h)
  441.         return false;
  442.  
  443.     // Compute step values.
  444.  
  445.     __int64 xfrac64, yfrac64, xaccum64, yaccum64;
  446.     unsigned long xfrac, yfrac;
  447.     int xistep;
  448.     PixOffset yistep;
  449.  
  450.     xfrac64 = (fabs(dx1)<1.0 ? 0.0 : dx1<0.0 ? dx1+1.0 : dx1-1.0)*4294967296.0 / (dx-1);    // round toward zero to avoid exceeding buffer
  451.     yfrac64 = (fabs(dy1)<1.0 ? 0.0 : dy1<0.0 ? dy1+1.0 : dy1-1.0)*4294967296.0 / (dy-1);
  452.  
  453.     xfrac = (unsigned long)xfrac64;
  454.     yfrac = (unsigned long)yfrac64;
  455.  
  456.     xistep = (long)(xfrac64 >> 32);            // round toward -oo
  457.     yistep = (long)(yfrac64 >> 32) * src->pitch;
  458.  
  459.     xaccum64 = (__int64)floor(x1*4294967296.0 + 0.5);
  460.     yaccum64 = (__int64)floor(y1*4294967296.0 + 0.5);
  461.  
  462.     if (dx1<0)
  463.         --xaccum64;
  464.     if (dy1<0)
  465.         --yaccum64;
  466.  
  467.     // Compute addresses.
  468.  
  469.     Pixel32 *srcp = src->Address32i((long)(xaccum64>>32), (long)(yaccum64>>32));
  470.     Pixel32 *dstp = Address32i(x2, y2);
  471.  
  472.     // Determine border sizes.  We have to copy pixels when xaccum >= (w-1)<<32
  473.     // or yaccum >= (h-1)<<32;
  474.  
  475.     int xprecopy=0, xpostcopy=0;
  476.     __int64 xborderval, yborderval;
  477.  
  478.     xborderval = ((__int64)(src->w-1)<<32);
  479.     yborderval = ((__int64)(src->h-1)<<32);
  480.  
  481.     if (xfrac64 < 0) {
  482.         if (xaccum64 >= xborderval) {
  483.             xprecopy = (xaccum64 - (xborderval-1) + xfrac64 - 1) / xfrac64 + 1;
  484.         }
  485.  
  486.         if (xprecopy > dx)
  487.             xprecopy = dx;
  488.  
  489.     } else {
  490.         if (xaccum64 + xfrac64*(dx-1) >= xborderval) {
  491.             xpostcopy = dx - ((xborderval - xaccum64 - 1)/xfrac64 + 1);
  492.         }
  493.  
  494.         if (xpostcopy > dx)
  495.             xpostcopy = dx;
  496.     }
  497.  
  498.     // Call texturing routine.
  499.  
  500.     if (dy) {
  501.         dx -= xprecopy + xpostcopy;
  502.  
  503.         asm_resize_bilinear(
  504.                 Address32i(x2, y2) + (dx+xprecopy),            // destination pointer, right side
  505.                 src->Address32i((long)(xaccum64>>32), (long)(yaccum64>>32)),
  506.                 -dx*4,
  507.                 dy,
  508.                 pitch,
  509.                 src->pitch,
  510.                 (unsigned long)xaccum64,
  511.                 (unsigned long)yaccum64,
  512.                 xfrac,
  513.                 yfrac,
  514.                 xistep,
  515.                 yistep,
  516.                 -xprecopy*4,
  517.                 -xpostcopy*4,
  518.                 src->Address32i(0, src->h-1));
  519.     }
  520.  
  521.     return true;
  522. }
  523.  
  524. bool VBitmap::RectFill(PixCoord x, PixCoord y, PixDim dx, PixDim dy, Pixel32 c) const throw() {
  525.  
  526.     if (depth != 32)
  527.         return false;
  528.  
  529.     // Do the blit
  530.  
  531.     Pixel32 *dstp;
  532.  
  533.     if (dx == -1) dx = w;
  534.     if (dy == -1) dy = h;
  535.  
  536.     // clip to destination bitmap
  537.  
  538.     if (x < 0) { dx+=x; x=0; }
  539.     if (y < 0) { dy+=y; y=0; }
  540.     if (x+dx > w) dx=w-x;
  541.     if (y+dy > h) dy=h-y;
  542.  
  543.     // anything left to fill?
  544.  
  545.     if (dx<=0 || dy<=0) return false;
  546.  
  547.     // compute coordinates
  548.  
  549.     dstp = Address32(x, y+dy-1);
  550.  
  551.     // do the fill
  552.  
  553.     do {
  554.         PixDim dxt = dx;
  555.         Pixel32 *dst2 = dstp;
  556.  
  557.         do {
  558.             *dst2++ = c;
  559.         } while(--dxt);
  560.  
  561.         dstp = (Pixel32 *)((char *)dstp + pitch);
  562.     } while(--dy);
  563.  
  564.     return true;
  565. }
  566.  
  567.